package com.zwh.se.oop.comprehensive;

/**
 * 鉴于this、super、static的介绍太过杂乱了,看笔记不太方便,所以这里特地放一处出来
 *
 * @author yexi
 */
public class ClassToTestThis {
    private String name;
    private int age;
    protected String state = "优";

    static String ss = "ss";
    static int sd = 4;


    public String getName() {
        return name;
    }


    /**
     * this主要存在于两个位置：
     * 在构造器中：表示当前被创建的对象
     * 在方法中：哪一个对象调用this所在的方法，此时this就表示哪一个对象
     * this关键字表示当前对象的引用，一般用于类的内部，其内部存在一个地址，指向当前初始化的对象本身
     * 当new一个对象时，实际上产生了两个引用，一个是供类内部调用其成员变量和成员方法的 this 关键字，
     * 一个是供外界程序调用实例成员实例对象ClassToTestThis
     * <p>
     * this 三种用法:
     * [1] 调用成员变量:主要用于当字段名字和局部变量发生重名的时候,由于就近原则的存在,会首先赋值给局部变量,也就是产生了局部变量和成员变量之间的二义性。
     * 此时就必须使用 this.字段 来解决这个问题。而如果不发生重名的话,实际上你完全可以忽略this。
     * [2] 调用其他实例方法:同一个类中非static方法间可以互相调用(虽然其实可以省略，但是为了可读性不建议省略)
     * [3] 调用本类其他构造方法。但注意:在构造方法中调用本类其他构造方法必须写到该构造方法第一句，否则出现编译错误。
     */
    public void setName(String name) {
        this.name = name;
    }


    //测试 this 的[3]
    public ClassToTestThis() {
        //有趣的是,如果此处不将这两个字段的修饰符改成static,编译器会报错：在调用父类型构造函数之前无法引用 'ClassToTestThis.ss'
        //这点是关于继承的知识,也就是所有对象在构造前jvm都会默认调用父类的无参构造器
        //但是,为什么jvm要这么做呢?为的就是在使用对象前能够给对象赋予初始值。
        //而如果该属性不使用static修饰(也就是该属性并不属于类所有而属于对象),那么jvm就会为了能正常使用而打算调用无参构造器
        //但是this构造器和super构造器只能同时存在一个(重点)。由于我在此处调用了this,这就意味着super构造器会被消去,而使用我的this构造器
        //但偏偏我使用的是有参构造器。也就是说,在此刻,ss和sd是处于未被初始化的状态,因此它们是没法被使用的。
        //所以编译器就会报错
        //TIPS:static修饰的字段由于在类加载的时候就初始化好了所以可以直接使用哦
        this(ss, sd);
    }


    public ClassToTestThis(String name, int age) {
        /*this();*/
        this.name = name;
        this.age = age;
    }

    public void sayName() {
        System.out.println("父亲名字:" + this.name);
    }

    @Override
    public String toString() {
        return "ClassToTestThis{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public static void main(String[] args) {
        ClassToTestThis ClassToTestThis = new ClassToTestThis();
        System.out.println(ClassToTestThis);
    }
}
